package com.gitee.kamismile.stone.basic.data.application.service;

import com.gitee.kamismile.stone.basic.data.application.rep.SysRoleRep;
import com.gitee.kamismile.stone.basic.data.application.req.command.role.RoleCreate;
import com.gitee.kamismile.stone.basic.data.application.req.command.role.RoleEdit;
import com.gitee.kamismile.stone.basic.data.application.req.command.role.RoleResCreate;
import com.gitee.kamismile.stone.basic.data.application.req.query.role.RoleQuery;
import com.gitee.kamismile.stone.basic.data.application.req.query.role.RoleResQuery;
import com.gitee.kamismile.stone.basic.data.domain.sysRes.repository.entity.SysResources;
import com.gitee.kamismile.stone.basic.data.domain.sysRes.service.ISysResDomainService;
import com.gitee.kamismile.stone.basic.data.domain.sysRole.repository.entity.SysRole;
import com.gitee.kamismile.stone.basic.data.domain.sysRole.repository.entity.SysRoleResources;
import com.gitee.kamismile.stone.basic.data.domain.sysRole.service.ISysRoleDomainService;
import com.gitee.kamismile.stone.basic.data.infrastructure.enums.CommonErrorEnum;
import com.gitee.kamismile.stone.basic.data.infrastructure.enums.RoleErrorEnum;
import com.gitee.kamismile.stone.basic.data.infrastructure.utils.CriteriaQueryBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
public class SysRoleServiceApplicationService {

    @Autowired
    private ISysResDomainService iSysResDomainService;

    @Autowired
    private ISysRoleDomainService iSysRoleDomainService;


    public Mono<SysRole> save(RoleCreate roleCreate, Integer nTenantId){
        Assert.notNull(nTenantId, CommonErrorEnum.TenantNotFound.getMessage());
        SysRole sysRole=new SysRole();
        BeanUtils.copyProperties(roleCreate, sysRole);
        sysRole.setnTenantId(nTenantId);
        return iSysRoleDomainService.saveOrUpdate(sysRole);
    }

    public Mono<SysRole> update(RoleEdit roleEdit, Integer nTenantId){
        Assert.notNull(nTenantId, CommonErrorEnum.TenantNotFound.getMessage());
        Assert.notNull(roleEdit.getnSysRoleId(), RoleErrorEnum.RoleNotNull.getMessage());;

        return iSysRoleDomainService.findAndCheckRoleById(roleEdit.getnSysRoleId(), nTenantId)
                .flatMap(v->{
                    SysRole sysRole=new SysRole();
                    BeanUtils.copyProperties(roleEdit, sysRole);
                    return   iSysRoleDomainService.saveOrUpdate(sysRole);
                });
    }

    public Mono<Void> deleteSysRoleById(Integer nSysRoleId,Integer nTenantId){
        Assert.notNull(nTenantId, CommonErrorEnum.TenantNotFound.getMessage());
        Assert.notNull(nSysRoleId, RoleErrorEnum.RoleNotNull.getMessage());;

        return iSysRoleDomainService.findAndCheckRoleById(nSysRoleId, nTenantId)
                .flatMap(v-> iSysRoleDomainService.deleteSysRoleById(nSysRoleId)
                );
    }

    public Mono<Page<SysRole>> findRolePage(RoleQuery roleQuery){
        Assert.notNull(roleQuery.getnTenantId(), CommonErrorEnum.TenantNotFound.getMessage());
        Criteria criteria = CriteriaQueryBuilder.builder()
                .likeIgnoreEmpty("sName", roleQuery.getsName())
                .inIgnoreEmpty("nTenantId", new Object[]{0,roleQuery.getnTenantId()})
                .create();
        return iSysRoleDomainService.findRolePage(roleQuery.getCurrentPage(),roleQuery.getPageSize(),criteria);
    }

    public Mono<SysRoleResources> save(RoleResCreate roleResCreate, Integer nTenantId){
        Assert.notNull(nTenantId, CommonErrorEnum.TenantNotFound.getMessage());
        SysRoleResources sysRoleResources=new SysRoleResources();
        BeanUtils.copyProperties(roleResCreate, sysRoleResources);
        sysRoleResources.setnTenantId(nTenantId);
        return iSysRoleDomainService.saveOrUpdate(sysRoleResources);
    }


    public Mono<Void> deleteSysRoleResById(Integer nSysRoleResourcesId,Integer nTenantId){
        Assert.notNull(nTenantId, CommonErrorEnum.TenantNotFound.getMessage());
        Assert.notNull(nSysRoleResourcesId, RoleErrorEnum.RoleResNotNull.getMessage());;

        return iSysRoleDomainService.findAndCheckRoleResById(nSysRoleResourcesId, nTenantId)
                .flatMap(v-> iSysRoleDomainService.deleteSysRoleResById(nSysRoleResourcesId,nTenantId)
                );
    }


    public Mono<Page<SysRoleRep>> findRoleResPage(RoleResQuery roleQuery){
        Assert.notNull(roleQuery.getnTenantId(), CommonErrorEnum.TenantNotFound.getMessage());
        Assert.notNull(roleQuery.getnSysRoleIds(), RoleErrorEnum.RoleNotNull.getMessage());;

        Criteria criteria = CriteriaQueryBuilder.builder()
                .inIgnoreEmpty("nSysRoleId", roleQuery.getnSysRoleIds())
                .inIgnoreEmpty("nTenantId", new Object[]{0,roleQuery.getnTenantId()})
                .create();
         return iSysRoleDomainService.findRoleResPage(roleQuery.getCurrentPage(),roleQuery.getPageSize(),criteria)
                 .flatMap(roleResPage -> {
                     List<SysRoleResources> roleResources = roleResPage.getContent();
                     if (CollectionUtils.isEmpty(roleResources)) {
                         // 如果为空，则直接返回空的SysRoleRep列表
                         return Mono.just(new PageImpl<SysRoleRep>(Collections.emptyList(), roleResPage.getPageable(), 0));
                     }

                     List<Integer> resourceIds = roleResources.stream()
                             .map(SysRoleResources::getnResourcesId)
                             .collect(Collectors.toList());

                     return iSysResDomainService.findResByIds(resourceIds)
//                             .defaultIfEmpty(new SysResources())
                             .collectList()
                             .map(resources -> resources.stream()
                                     .collect(Collectors.toMap(SysResources::getnResourcesId, Function.identity())))
                             .flatMapMany(resourcesMap -> Flux.fromIterable(roleResources)
                                     .map(roleResource -> {
                                         SysRoleRep sysRoleRep = new SysRoleRep();
                                         BeanUtils.copyProperties(roleResource, sysRoleRep);
                                         SysResources resource = resourcesMap.getOrDefault(roleResource.getnResourcesId(), new SysResources());
                                         BeanUtils.copyProperties(resource, sysRoleRep);
                                         return sysRoleRep;
                                     })
                                     ).collectList()
                             .map(sysRoleReps -> new PageImpl<SysRoleRep>(sysRoleReps, roleResPage.getPageable(), roleResPage.getTotalElements()));
                 });

    }



}
